/************************************************************************
* Programmer:  Philippe Gambling
*
* Course:  CSCI 4534
*
* Date:  February 18, 2009
*
* Assignment:  #1
*
* Environment:  GCC 3.2.2 running on diamond.rocks.uhcl.edu
*
* Files Included: client.c, server.c, fifomsg.h
*
* Purpose:  Receives an integer values from multiple client programs, 
*           calculates the average value of all integers sent by the clients, 
*           and returns the average to each client.
*
* Input:  The number of expected clients entered by the user,
*         a process id and an integer received from each client via FIFO_TO_SERVER.
*
* Preconditions:  The server program is started before the clients.
*
* Output:  The average value of all the integers received sent to each client via FIFO_PID.
*
* Postconditions:  The server terminates after sending the result to each client.
*                  FIFO_TO_SERVER is deleted.
*
* Algorithm:
*          Prompt user for the number of clients, 
*           exit if less than 3 or greater than MAX_NUM_CLIENTS
*          Create FIFO_TO_SERVER
*          Open FIFO_TO_SERVER as read only
*          Loop until data read from the expected number of clients
*            Read a fifomsg struct from FIFO_TO_SERVER to fifomsg array
*            Copy the integer from the received fifomsg to integer array
*          Calculate average of the three integers and store in a float
*          For each element in fifomsg array
*            Assign average value to fifomsg result attribute
*            Open clientFifoName as write only (clientFifoName is the private fifo 
*            name received from client)
*            Write the fifomsg to clientFifoName
*            Close clientFifoName
*          Close FIF0_TO_SERVER
*          Unlink FIFO_TO_SERVER
***********************************************************************/ 


#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/errno.h>
#include <fcntl.h>

/* Custom includes created for this assignment */
#include "fifomsg.h"  // Defines a struct to receive data from client

#define MAX_NUM_CLIENTS 25 // Maximum number of clients supported by server

/* Function prototypes */
float CalcAverage(const int *,int);

extern int errno;

int main (void)
{
  int fda;		// to read from client
  int fdb;		// to write to client
  int bytes = 0;	// Bytes read from FIFO_TO_SERVER
  int i;      // Loop counter   
  int numClients = 0; // Number of clients

  fifomsg fromClient[MAX_NUM_CLIENTS] = {{{0},0,0}}; // Data received from client
  int nums[MAX_NUM_CLIENTS] = {0}; // Integers received from all clients
  float average = 0; // average of numbers received from client

  // Get expected number of clients from user
  printf("Server: How many clients will connect (between 3 and %d)? ", MAX_NUM_CLIENTS);
  scanf("%d", &numClients);
  // Make sure number of clients is at least 3 and did not exceed MAX_NUM_CLIENTS
  if(numClients<3) 
  {
    perror("Number of clients must be at least 3, exiting...");
	  exit(-2);
  }
  else
  if(numClients>MAX_NUM_CLIENTS)
  {
    perror("Number of clients can not exceed maximum number of clients, exiting...");
	  exit(-3);
  }

  // Create the FIFO_TO_SERVER
  if ((mkfifo("FIFO_TO_SERVER",0666)<0 && errno != EEXIST))
  {
	  perror("cant create FIFO_TO_SERVER");
	  exit(-1);
  }

  // Open FIFO_TO_SERVER to receive data from clients
  if((fda=open("FIFO_TO_SERVER", O_RDONLY))<0)
	  printf("cant open FIFO_TO_SERVER to read");

  // Handle each clients request
  i = 0;
  while(i<numClients)
  {
    // Read data from client
    if(read(fda, &fromClient[i], sizeof(fifomsg))>0) 
    { 
      printf("Server: Bytes read from fifo %d\n",bytes);
      printf("Server: Received the following message from client: \n");
      printf("        clientFifoName: %s\n",fromClient[i].clientFifoName);
      printf("        param: %d\n",fromClient[i].param); 
      printf("        result: %f\n",fromClient[i].result); 
      
      nums[i] = fromClient[i].param;
      
      i++;  // Increment loop counter if more than 0 bytes read
    }
  }

  // Calculate the average client values
  average = CalcAverage(nums,numClients);
  printf("Server: average is %f\n", average);
  
  for(i=0;i<numClients;i++)
  {
    // Assign result to each fifomsg
    fromClient[i].result = average;
    
    // Open clientFifoName to send data to clients
    if((fdb=open(fromClient[i].clientFifoName, O_WRONLY))<0) {
      printf("cant open %s to write", fromClient[i].clientFifoName); }
    
    // Send the result back to each client
    write(fdb, &fromClient[i], sizeof(fifomsg));
    printf("Server: Sent the average to client\n");
    
    close(fdb);
  }
  
  printf("Server: all done, Disconnecting.\n ");

  close(fda);
  unlink("FIFO_TO_SERVER");
  
  return 0;
}

float CalcAverage(const int * nums,int numElements)
/************************************************************************
* Purpose:  To calculate the average of all numbers in an integer array
*
* Parameters:  An integer array and the number of elements in the array
*
* Action:  A float with the average of the integers is returned
*
* Algorithm: Find the sum of all elements and divide by number of elements.
*            Sum is casted as a float to produce a floating point result.
***********************************************************************/ 
{
  int sum = 0; // Sum of all elements in integer array
  int i = 0; // Loop counter
  
  for(i=0;i<numElements;i++) { sum += nums[i]; } // Add up all the integers
  return (float)sum/numElements;
}
